import { Callout } from '@/components'

# lazy

<Callout type='experimental'>

`lazy` is an experimental feature, so this interface may change.

</Callout>

The `lazy` function is a wrapper around React's `lazy` function that provides callbacks for component loading success and failure. It allows you to execute custom logic when a component loads successfully or fails, providing better user experience and debugging capabilities.

### Preloading Components

By default, `lazy` works the same as React's `lazy` but provides an additional `load` method.

```tsx /Component.load/
import { lazy, Suspense } from '@suspensive/react'

const Component = lazy(() => import('./Component'))

function PreloadExample() {
  return (
    <div>
      <button onClick={() => Component.load()}>Preload Component</button>
      <Suspense fallback={<div>Loading...</div>}>
        <Component />
      </Suspense>
    </div>
  )
}
```

### Success/Error Callbacks

```tsx /onSuccess/ /onError/
import { lazy, Suspense, ErrorBoundary } from '@suspensive/react'

const UserProfile = lazy(() => import('./UserProfile'), {
  onSuccess: () => console.log('Component loaded successfully'),
  onError: ({ error }) => console.error('Loading failed:', error),
})

function App() {
  return (
    <ErrorBoundary fallback={<div>Something went wrong</div>}>
      <Suspense fallback={<div>Loading...</div>}>
        <UserProfile />
      </Suspense>
    </ErrorBoundary>
  )
}
```

## createLazy

Creates a lazy function with custom default options.

```tsx /createLazy/
import { createLazy } from '@suspensive/react'

const lazy = createLazy({
  onSuccess: () => console.log('Component loaded successfully'),
  onError: ({ error }) => console.error('Component loading failed:', error),
})

const Component = lazy(() => import('./Component'))
```

### Callback Execution Order

- **onSuccess**: Individual callback → Default callback
- **onError**: Individual callback → Default callback

```tsx /onSuccess/ /onError/
import { createLazy } from '@suspensive/react'

const lazy = createLazy({
  onSuccess: () => console.log('2. Default onSuccess'),
  onError: ({ error }) => console.log('2. Default onError:', error),
})

const Component = lazy(() => import('./Component'), {
  onSuccess: () => console.log('1. Individual onSuccess'),
  onError: ({ error }) => console.log('1. Individual onError:', error),
})

// Execution order when component loads successfully:
// 1. Individual onSuccess
// 2. Default onSuccess

// Execution order when component fails to load:
// 1. Individual onError
// 2. Default onError
```

## reloadOnError

The `reloadOnError` function provides a convenient way to automatically reload the page when component loading fails. This is particularly useful for handling version skew issues in production environments.

**Background:** While the best approach to solve version skew problems is to handle them at the infrastructure level (e.g., proper deployment strategies, CDN cache invalidation), there are cases where this is not possible or practical. `reloadOnError` serves as a client-side fallback solution for such scenarios.

### Version Skew Problem Resolution

```tsx /reloadOnError/
import { lazy, reloadOnError } from '@suspensive/react'

const MAX_RELOADS = 3

const VersionSkewSafeComponent = lazy(
  () => import('./VersionSkewSafeComponent'),
  reloadOnError({
    retry: MAX_RELOADS,
    retryDelay: 1000,
  })
)
```

<Callout type="info">

**If implemented without reloadOnError:**

```diff
+ import { lazy, reloadOnError } from '@suspensive/react'
- import { createLazy } from '@suspensive/react'

+ const Component = lazy(() => import('./Component'), reloadOnError({
+   retry: 3,
+   retryDelay: 1000,
+ }))
- const Component = lazy(() => import('./Component'), {
-   onError: ({ error, load }) => {
-     const reloadKey = 'component_reload_count'
-     const currentCount = parseInt(sessionStorage.getItem(reloadKey) || '0')
-     const maxRetries = 3
-
-     if (currentCount < maxRetries && error.message?.includes('Loading chunk')) {
-       const newCount = currentCount + 1
-       sessionStorage.setItem(reloadKey, newCount.toString())
-
-       setTimeout(() => {
-         window.location.reload()
-       }, 1000)
-     }
-   },
-   onSuccess: ({ load }) => {
-     // Clear reload count on success
-     sessionStorage.removeItem('component_reload_count')
-   },
- })

const Component = lazy(() => import('./Component'))
```

</Callout>

### Custom Storage and Reload Function

```tsx /storage:/ /reload:/
import { createLazy, reloadOnError } from '@suspensive/react'

const customStorage = {
  getItem: (key) => localStorage.getItem(key),
  setItem: (key, value) => localStorage.setItem(key, value),
  removeItem: (key) => localStorage.removeItem(key),
}

const customReload = () => {
  // Custom reload logic
  window.location.href = window.location.href
}

const lazy = createLazy(
  reloadOnError({
    retry: 5,
    retryDelay: 2000,
    storage: customStorage,
    reload: customReload,
  })
)

const Component = lazy(() => import('./Component'))
```
